package uml.structural.proxy.jdk;

import lombok.extern.slf4j.Slf4j;
import org.xml.sax.SAXException;
import util.bean.BeanUtil;

import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * on 2023/1/9 23:14
 */
@Slf4j
public class ProxyClassGenerator<T> {
    /**
     * 被代理的对象（真实对象）
     */
    private T proxiedObj;

    public ProxyClassGenerator(Class<T> c, File config, String proxiedClassName) throws ParserConfigurationException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SAXException {
        this.proxiedObj = BeanUtil.newBean(c, config, proxiedClassName);
    }

    public T generateProxyClassInstance() {
        Class<T> c = (Class<T>) proxiedObj.getClass();
//        设置系统属性，保存动态代理类class文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        return (T) Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] methodArgs) throws Throwable {
                // 前置处理
                preInvoke(proxy,method, methodArgs);
                // 执行被代理对象的方法
                Object result = invoking(method, proxiedObj, methodArgs);
                // 后置处理
                return postInvoke(proxy,method, result);
            }

            /**
             * 调用前
             * @param method
             * @param args
             */
            private void preInvoke(Object proxy, Method method, Object... args) {
                log.debug("{},前置处理 >>>",method.getName());
                log.debug("方法接收参数：{}", Arrays.toString(args));
                log.debug("{},前置处理 <<<",method.getName());
            }

            /**
             * 调用中......
             * @param method
             * @param proxiedObj
             * @param methodArgs
             */
            private Object invoking(Method method, Object proxiedObj, Object... methodArgs) throws Exception {
                try {
                    return method.invoke(proxiedObj, methodArgs);
                } catch (Exception e) {
                    // 异常处理
                    afterThrowing(method, e);
                }
                return null;
            }

            /**
             * 调用返回后
             * @param proxy
             * @param method
             * @param res
             */
            private Object postInvoke(Object proxy, Method method, Object res) {
                log.debug("{},后置处理",method.getName());
                return res;
            }

            /**
             * 将被代理对象方法产生的异常抛给代理对象的调用者
             * @param
             * @param
             */
            private void afterThrowing(Method method, Exception e) throws Exception {
                log.debug("{},异常处理",method.getName());
                throw e;
            }
        });
    }
}
